﻿namespace Subtitles.Formats.Srt
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Globalization;
    using System.IO;
    using System.Text;

    using MEF_Test.Bricks.StronglyTypedExports;
    using MEF_Test.Bricks.Subtitles;
    using MEF_Test.Contracts;
    using MEF_Test.Subtitles;

    [Export(typeof(ISubtitleFormatHandler))]
    [SubtitleFormatHandlerExport(FileExtension = "srt")]    
    public class SrtSubtitleFormatHandler : ISubtitleFormatHandler
    {
        public ISubtitleHandler Create(Stream subtitle)
        {
            if (subtitle == null) throw new ArgumentNullException("subtitle");
            
            var subtitleText = new StreamReader(subtitle);
            ISubtitleHandler subtitleHandler = new SubtitleHandler();
            while (!subtitleText.EndOfStream)
            {
                int subNumber;

                var subNumberString = string.Empty;

                // Flush the padding.
                while (subNumberString == string.Empty)
                {
                    subNumberString = subtitleText.ReadLine();
                }

                //var subNumberString = subtitleText.ReadLine();
                bool success = int.TryParse(subNumberString, out subNumber);

                if (!success)
                {
                    throw new FormatException("The subtitle format has not been recognized as valid for a srt subtitle file : The sub number could not be read.");
                }

                var timeStampLine = subtitleText.ReadLine();
                if (timeStampLine == null)
                {
                    throw new FormatException("The subtitle format has not been recognized as valid for a srt subtitle file : The time stamps could not be read.");                    
                }

                // Element 0 and 2 contain string-representation of the -respectively- start and end time stamps. element 1 *always* contains the arrow "-->".
                // It's a bit messy, but it's more effective than a regular expression.
                var timeStamp = timeStampLine.Split(' ');

                // SubRip Text format is a french format : see http://en.wikipedia.org/wiki/SubRip#SubRip_text_file_format
                TimeSpan timeStart = TimeSpan.Parse(timeStamp[0], new CultureInfo("fr-fr"));
                TimeSpan timeEnd = TimeSpan.Parse(timeStamp[2], new CultureInfo("fr-fr"));

                var line = subtitleText.ReadLine();
                var dialog = new StringBuilder(line);
                
                while (!string.IsNullOrEmpty(line))
                {
                    line = subtitleText.ReadLine();
                    dialog.AppendLine(line);
                }

                // Build subtitleEntry
                var subtitleEntry = new SubtitleEntry(subNumber, timeStart, timeEnd, dialog.ToString());
                subtitleHandler.Append(subtitleEntry);
            }            
            return subtitleHandler;
        }
    }

    public class SubtitleEntry : ISubtitleEntry
    {
        /// <summary>
        /// the number of the subtitle in the sequence
        /// </summary>
        private readonly int _subNumber;

        /// <summary>
        /// The time span between the begining of the video and the position where the dialog line appears
        /// </summary>
        private readonly TimeSpan _timeStart;
        
        /// <summary>
        /// The time span between the begining of the video and the position where the dialog line disappears
        /// </summary>
        private readonly TimeSpan _timeEnd;

        /// <summary>
        /// The text to display on screen.
        /// </summary>
        private readonly string _dialogLine;

        /// <summary>
        /// Initializes a new instance of the <see cref="SubtitleEntry"/> class.
        /// </summary>
        /// <param name="subNumber">The sub number.</param>
        /// <param name="timeStart">The time elapsed from the beginning of the video before the subtitle starts.</param>
        /// <param name="timeEnd">The time elapsed from the beginning of the video before the subtitle ends.</param>
        /// <param name="dialogLine">The dialog line.</param>
        public SubtitleEntry(int subNumber, TimeSpan timeStart, TimeSpan timeEnd, string dialogLine)
        {
            _subNumber = subNumber;
            _timeStart = timeStart;
            _timeEnd = timeEnd;
            _dialogLine = dialogLine;            
        }

        /// <summary>
        /// Gets the dialog line.
        /// </summary>
        /// <value>The text to show on-screen.</value>
        public string DialogLine
        {
            get
            {
                return this._dialogLine;
            }
        }

        /// <summary>
        /// Gets or sets the start time.
        /// </summary>
        /// <value>The start.</value>
        public TimeSpan Start
        {
            get
            {
                return _timeStart;
            }
            
        }

        /// <summary>
        /// Gets or sets the duration.
        /// </summary>
        /// <value>The duration.</value>
        public TimeSpan Duration
        {
            get
            {
                return _timeEnd.Subtract(_timeStart);
            }
            set { throw new NotImplementedException(); }
        }
    }
}